package serviceset1.feign

import au.com.dius.pact.consumer.PactVerificationResult
import au.com.dius.pact.consumer.groovy.PactBuilder
import com.netflix.config.ConfigurationManager
import com.netflix.hystrix.Hystrix
import com.netflix.hystrix.HystrixCircuitBreaker
import com.netflix.hystrix.HystrixCommandKey
import com.netflix.hystrix.HystrixCommandMetrics
import feign.Feign
import feign.gson.GsonDecoder
import feign.httpclient.ApacheHttpClient
import grails.gorm.transactions.Rollback
import grails.testing.mixin.integration.Integration
import org.springframework.beans.factory.annotation.Autowired

//import org.springframework.boot.test.context.SpringBootTest
import spock.lang.Specification

//@SpringBootTest(properties = [
//    // overriding provider address
//    "feign.client.config.SERVICE-SET-2.url: localhost:1234"
//])
@Integration
@Rollback
class ServiceSet2Spec extends Specification {

    //FeignClientInterfaceName#MethodNameWithSignatures
    private static final CommandKey = "ServiceSet2#sampleApi2(String)"

    @Autowired
    private ServiceSet2 serviceSet2

    def setupSpec() {
        Hystrix.reset()
    }

    def setup() {
    }

    def cleanup() {
    }

    void "test fallback"() {
        given:
        def dependency = "feign"

        when: "The circuit breaker is open when call the method 'process'."
        def result = serviceSet2.sampleApi2(dependency)
        then:
        result instanceof Map
        result.state == "offline"
        result.provider == "sampleApi2@serviceSet2"
        result.dependency == dependency
    }

    void "shouldTripCircuit"() {
        given:
        ConfigurationManager.getConfigInstance().setProperty("hystrix.command.${CommandKey}.circuitBreaker.requestVolumeThreshold", 1)
        def circuitBreaker = HystrixCircuitBreaker.Factory.getInstance(HystrixCommandKey.Factory.asKey(CommandKey))

        when: "nothing to do"

        // demonstrates circuit is actually closed
        then:
        !circuitBreaker.isOpen()
        circuitBreaker.allowRequest()

        when:
        serviceSet2.sampleApi2("feign")

        and:
        /*
        waitUntilCircuitBreakerOpens
        one second is almost sufficient
        borrowed from https://github.com/Netflix/Hystrix/blob/v1.5.5/hystrix-core/src/test/java/com/netflix/hystrix/HystrixCircuitBreakerTest.java#L140
         */
        sleep 1000

        then:
        circuitBreaker.isOpen()
        !circuitBreaker.allowRequest()
    }

    void "shouldHaveCustomTimeout"() {
        expect: "Check timeoutInMilliseconds flow the custom by @HystrixCommand.commandProperties or default configuration"
        HystrixCommandMetrics.getInstance(HystrixCommandKey.Factory.asKey(CommandKey)).getProperties().executionTimeoutInMilliseconds().get() == 12000
    }

    void "test some logic via mock sampleApi2@SERVICE-SET-2"() {
        given:
        def dependency = "feign"
        def mockProvider = new PactBuilder() // Create a new PactBuilder
        mockProvider {
            serviceConsumer "serviceSet2"    // Define the service consumer by name
            hasPactWith "SERVICE-SET-2"   // Define the service provider that it has a pact with
            port 1234
            // The port number for the service. It is optional, leave it out to use a random one

            //given('there is a rest api') // defines a provider state. It is optional.
            uponReceiving('a request to GET result of /sampleApi2') // upon_receiving starts a new interaction
            withAttributes(method: 'get', path: '/sampleApi2', query: [dependency: dependency])
            // define the request, a GET request to '/sampleApi2'
            willRespondWith(                        // define the response we want returned
                    status: 200,
                    headers: ['Content-Type': 'application/json'],
                    body: [provider: "sampleApi2@serviceSet2", dependency: dependency]
            )
        }

        when:
        def result = mockProvider.runTest { mockServer ->
            def serviceSet2 = Feign.builder()
                    .client(new ApacheHttpClient())
                    .decoder(new GsonDecoder())
                    .target(ServiceSet2.class, mockServer.url as String)

            def resp = serviceSet2.sampleApi2(dependency)
            assert resp instanceof Map
            assert resp.state == null
            assert resp.provider == "sampleApi2@serviceSet2"
            assert resp.dependency == dependency
        }

        then:
        result == PactVerificationResult.Ok.INSTANCE  // This means it is all good
    }
}
